#pragma warning(disable:4005)
#include <drogon/HttpController.h>
#include "OCServer/DocGenerate.h"
#include "OCServer/AliasManager.h"
#include "OCMain/ZipUtil.h"

using namespace drogon;
using namespace OCPP;

inline void setGZIp(HttpResponsePtr& resp)
{
	resp->addHeader("Content-Encoding", "gzip");
}

std::string url_decode(const std::string& url) {
	std::string result;
	for (size_t i = 0; i < url.length(); i++) {
		if (url[i] == '%' && i + 2 < url.length()) {
			int hex_val;
			std::istringstream(url.substr(i + 1, 2)) >> std::hex >> hex_val;
			result += static_cast<char>(hex_val);
			i += 2;  // Skip the next two characters
		}
		else {
			result += url[i];
		}
	}
	return result;
}

class AliasService : public HttpController<AliasService>
{
public:
	METHOD_LIST_BEGIN
		METHOD_ADD(AliasService::home, "", Get);
	METHOD_ADD(AliasService::alias, "/{}", Get);
	METHOD_ADD(AliasService::alias, "/{}/{}", Get);
	METHOD_ADD(AliasService::alias, "/{}/{}/{}", Get);
	METHOD_ADD(AliasService::alias, "/{}/{}/{}/{}", Get);
	METHOD_ADD(AliasService::alias, "/{}/{}/{}/{}/{}", Get);
	METHOD_ADD(AliasService::alias, "/{}/{}/{}/{}/{}/{}", Get);
	METHOD_ADD(AliasService::alias, "/{}/{}/{}/{}/{}/{}/{}", Get);
	METHOD_ADD(AliasService::alias, "/{}/{}/{}/{}/{}/{}/{}/{}", Get);
	METHOD_LIST_END
		AliasService()
	{
	}
protected:
	void home(const HttpRequestPtr& req,
		std::function<void(const HttpResponsePtr&)>&& callback)
	{
		auto resp = HttpResponse::newHttpResponse();
		resp->setBody("AliasService");
		callback(resp);

	}
	void alias(const HttpRequestPtr& req,
		std::function<void(const HttpResponsePtr&)>&& callback)
	{
		auto resp = HttpResponse::newHttpResponse();
	
		String requestPath = url_decode(req->getOriginalPath());
		requestPath = requestPath.substr(14, requestPath.length());
		auto i = requestPath.find_first_of('/');
		String alias = requestPath.substr(0, i);
		String filePath = requestPath.substr(i + 1, requestPath.length());
		String fileName = Singleton(AliasManager).getFilePath(alias, filePath);
		String gzFileName = fileName;
		if (!StringUtil::endsWith(fileName, ".gz", false))
		{
			gzFileName += ".gz";
		}

		if (!FileUtil::existFile(fileName) && !FileUtil::existFile(gzFileName))
		{
			resp = HttpResponse::newNotFoundResponse();
		}
		else
		{
			String gzContent;
			String name = fileName.substr(fileName.find_last_of('/') + 1, fileName.length());

			if (FileUtil::existFile(gzFileName))
			{
				gzContent = FileUtil::getFileBinary(gzFileName);
			}
			else if (Singleton(AliasManager).isAutoMakeGZ(alias))
			{
				String raw = FileUtil::getFileBinary(fileName);
				gzContent = ZipUtil::gzipCompress(raw);
				FileUtil::writeFile(gzFileName, gzContent);
			}

			if (gzContent.size() > 0)
			{
				resp = drogon::HttpResponse::newFileResponse((const unsigned char*)gzContent.data(), gzContent.length(), name,
					CT_APPLICATION_OCTET_STREAM);
				setGZIp(resp);
			}
			else
			{
				String content = FileUtil::getFileBinary(fileName);
				resp->setBody(content);
			}
		}

		callback(resp);
	}
};